import os
import sys
import time
import json
import requests
import threading
import tkinter as tk
from tkinter import messagebox, ttk
from urllib.parse import urlparse
import configparser
import re
import platform
import subprocess

# 应用程序配置
APP_NAME = "核桃夹更新程序"
LOCAL_VERSION_FILE = "version.ini"
VERSION_PATTERN = r'^v?\d+\.\d+(\.\d+)?$'
UPDATE_DIR = os.getcwd()
DOWNLOAD_DIR = os.path.join(UPDATE_DIR, "updates")  # 下载文件专用文件夹


def get_default_config():
    """获取默认配置"""
    config = configparser.ConfigParser()
    config['select'] = {
        'version': 'v1.0.0',
        'url': 'http://159.75.119.133:3000/api/check'
    }
    return config


def read_or_create_config():
    """读取或创建配置文件"""
    config = get_default_config()
    if os.path.exists(LOCAL_VERSION_FILE):
        try:
            config.read(LOCAL_VERSION_FILE)
            print(f"成功读取配置文件: {LOCAL_VERSION_FILE}")
        except Exception as e:
            print(f"读取配置文件失败: {e}")
            with open(LOCAL_VERSION_FILE, 'w') as f:
                config.write(f)
    else:
        with open(LOCAL_VERSION_FILE, 'w') as f:
            config.write(f)
            print(f"创建默认配置文件: {LOCAL_VERSION_FILE}")
    return config


# 读取配置
config = read_or_create_config()
CURRENT_VERSION = config['select'].get('version', 'v1.0.0').strip()
UPDATE_SERVER_URL = config['select'].get('url', 'http://159.75.119.133:3000/api/check').strip()


class Updater:
    def __init__(self):
        self.update_url = None
        self.new_version = None
        self.download_path = None
        self.local_version = CURRENT_VERSION
        self.force_update = False
        self.update_description = "暂无更新描述"
        self.server_url = UPDATE_SERVER_URL
        self.root = None

        # 创建下载目录
        self.ensure_download_dir()

    def ensure_download_dir(self):
        """确保下载目录存在"""
        if not os.path.exists(DOWNLOAD_DIR):
            os.makedirs(DOWNLOAD_DIR)
            print(f"创建下载目录: {DOWNLOAD_DIR}")

    def check_local_config(self):
        """检查并更新本地配置"""
        global CURRENT_VERSION, UPDATE_SERVER_URL
        try:
            if os.path.exists(LOCAL_VERSION_FILE):
                config = configparser.ConfigParser()
                config.read(LOCAL_VERSION_FILE)
                if 'select' in config:
                    version = config['select'].get('version', 'v1.0.0').strip()
                    if re.match(VERSION_PATTERN, version):
                        self.local_version = version
                        CURRENT_VERSION = version
                    else:
                        print(f"版本号格式错误: {version}，使用默认版本")
                        self.local_version = CURRENT_VERSION

                    url = config['select'].get('url', UPDATE_SERVER_URL).strip()
                    self.server_url = url
                    UPDATE_SERVER_URL = url
                return True
        except Exception as e:
            print(f"读取本地配置失败: {e}")
        return False

    def normalize_version(self, version):
        """规范化版本号格式"""
        if version and not version.startswith('v'):
            return f"v{version}"
        return version

    def is_newer_version(self, new_ver, old_ver):
        """比较版本号是否更新"""
        new_ver = self.normalize_version(new_ver)
        old_ver = self.normalize_version(old_ver)
        try:
            new_nums = tuple(map(int, re.findall(r'\d+', new_ver)))
            old_nums = tuple(map(int, re.findall(r'\d+', old_ver)))
            return new_nums > old_nums
        except:
            return False

    def clean_download_dir(self):
        """清空下载目录中的临时文件"""
        try:
            print("开始清理下载目录...")
            for filename in os.listdir(DOWNLOAD_DIR):
                filepath = os.path.join(DOWNLOAD_DIR, filename)
                if filename.endswith(('.part', '.complete', '.old')):
                    os.remove(filepath)
                    print(f"删除临时文件: {filename}")
            print("下载目录清理完成")
        except Exception as e:
            print(f"清理下载目录失败: {e}")

    def check_local_update_file(self):
        """检查本地是否存在新版本文件"""
        if not self.check_local_config():
            return False

        if not self.check_update():
            return False

        expected_filename = f"{self.new_version}.exe"
        expected_filepath = os.path.join(DOWNLOAD_DIR, expected_filename)

        if os.path.exists(expected_filepath):
            print(f"发现本地更新文件: {expected_filename}")
            self.download_path = expected_filepath
            return True

        return False

    def cleanup_old_files(self):
        """清理旧的下载文件和临时文件"""
        try:
            print("开始清理旧文件...")
            self.clean_download_dir()
            print("旧文件清理完成")
            return True
        except Exception as e:
            print(f"清理旧文件失败: {e}")
            return False

    def check_update(self):
        """检查是否有新版本"""
        if not self.check_local_config():
            return False

        try:
            normalized_local = self.normalize_version(self.local_version)
            response = requests.get(self.server_url, params={"current_version": normalized_local})

            if response.status_code == 200:
                data = response.json()

                # 提取results数组中的第一个元素
                results = data.get("results", [])
                if not results:
                    print("服务器返回的results数组为空")
                    return False

                update_info = results[0]

                # 检查是否有可用更新（字符串"1"表示True）
                update_available = update_info.get("update_available", "0") == "1"
                if not update_available:
                    return False

                server_version = update_info.get("version")
                # 将字符串"1"/"0"转换为布尔值
                self.force_update = update_info.get("force_update", "0") == "1"
                self.update_description = update_info.get("description", "暂无更新描述")

                if server_version and self.is_newer_version(server_version, self.local_version):
                    self.new_version = server_version
                    self.update_url = update_info.get("download_url")
                    return True

            return False
        except Exception as e:
            print(f"检查更新失败: {e}")
            return False

    def download_update(self, progress_callback=None):
        """下载更新文件到专用目录"""
        if not self.update_url:
            return False

        try:
            filename = os.path.basename(urlparse(self.update_url).path)
            self.download_path = os.path.join(DOWNLOAD_DIR, filename)
            temp_download_path = self.download_path + ".part"
            download_complete_flag = self.download_path + ".complete"

            for f in [temp_download_path, download_complete_flag]:
                if os.path.exists(f):
                    os.remove(f)

            response = requests.get(self.update_url, stream=True)
            total_size = response.headers.get('content-length')
            total_size = int(total_size) if total_size is not None else None

            block_size = 1024
            downloaded_size = 0

            with open(temp_download_path, 'wb') as f:
                for data in response.iter_content(block_size):
                    downloaded_size += len(data)
                    f.write(data)
                    if progress_callback:
                        if total_size is not None:
                            progress = (downloaded_size / total_size) * 100
                            progress_callback(progress)

            os.replace(temp_download_path, self.download_path)
            with open(download_complete_flag, 'w') as f:
                f.write("1")

            return True
        except Exception as e:
            print(f"下载更新失败: {e}")
            for f in [temp_download_path, download_complete_flag]:
                if os.path.exists(f):
                    os.remove(f)
            return False

    def rename_to_version_exe(self):
        """将下载的文件重命名为版本号并添加.exe后缀"""
        if not self.download_path or not os.path.exists(self.download_path):
            return False

        try:
            new_filename = f"{self.new_version}.exe"
            new_filepath = os.path.join(DOWNLOAD_DIR, new_filename)

            # 如果目标文件已存在，先删除
            if os.path.exists(new_filepath):
                os.remove(new_filepath)

            os.rename(self.download_path, new_filepath)
            self.download_path = new_filepath
            print(f"文件已重命名为: {new_filepath}")
            return True
        except Exception as e:
            print(f"重命名文件失败: {e}")
            return False

    def close_target_program(self):
        """关闭目标程序（核桃夹.exe）"""
        program_name = "核桃夹.exe"
        try:
            current_os = platform.system()
            if current_os == "Windows":
                # Windows系统使用taskkill命令
                subprocess.run(["taskkill", "/F", "/IM", program_name], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                print(f"已成功关闭程序: {program_name}")
                return True
            elif current_os == "Linux" or current_os == "Darwin":
                # Linux或macOS系统使用pkill命令
                subprocess.run(["pkill", "-f", program_name], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                print(f"已成功关闭程序: {program_name}")
                return True
            else:
                print(f"不支持的操作系统: {current_os}，无法关闭程序")
                return False
        except subprocess.CalledProcessError:
            print(f"程序 {program_name} 未运行或关闭失败（可能权限不足）")
            return False
        except Exception as e:
            print(f"关闭程序时发生未知错误: {e}")
            return False

    def install_update(self):
        """安装更新程序（直接运行updates目录中的文件）"""
        if not self.rename_to_version_exe():
            if self.root:
                messagebox.showerror("错误", "文件重命名失败，无法安装更新")
            return False

        if not self.download_path or not os.path.exists(self.download_path):
            if self.root:
                messagebox.showerror("错误", "更新文件不存在")
            return False

        try:
            # 安装前关闭目标程序
            if self.close_target_program():
                print("程序已关闭，准备安装更新...")
            else:
                # 关闭失败时给出提示，但继续尝试安装
                if self.root:
                    messagebox.showwarning("提示", "关闭程序失败，可能需要手动关闭后再安装")

            if self.download_path.lower().endswith(('.exe', '.msi')):
                os.system(f'"{self.download_path}"')
            else:
                if self.root:
                    messagebox.showerror("错误", f"不支持的安装包类型: {self.download_path}")
                return False

            # 更新本地配置文件
            config = configparser.ConfigParser()
            config['select'] = {
                'version': self.new_version,
                'url': self.server_url
            }
            with open(LOCAL_VERSION_FILE, 'w') as f:
                config.write(f)

            self.local_version = self.new_version

            # 安装完成后清理临时文件（保留安装包）
            self.clean_download_dir()

            return True
        except Exception as e:
            print(f"安装更新失败: {e}")
            if self.root:
                messagebox.showerror("错误", f"安装更新失败: {e}")
            return False


def create_gui(updater):
    """创建GUI界面"""
    root = tk.Tk()
    root.title(f"{APP_NAME} 更新程序")
    root.geometry("400x320")
    root.resizable(False, False)
    root.option_add("*Font", ('SimHei', 10))
    updater.root = root

    status_var = tk.StringVar(value="正在初始化...")
    status_label = tk.Label(root, textvariable=status_var, wraplength=380)
    status_label.pack(pady=10)

    version_var = tk.StringVar(value="")
    version_label = tk.Label(root, textvariable=version_var, font=('SimHei', 9))
    version_label.pack(pady=5)

    desc_label = tk.Label(root, text="更新描述:", anchor="w", wraplength=380)
    desc_label.pack(pady=(5, 0), fill="x", padx=10)

    desc_text = tk.Text(root, height=6, width=45, wrap=tk.WORD, font=('SimHei', 9))
    desc_text.pack(pady=5, fill="both", expand=True, padx=10)
    desc_text.config(state=tk.DISABLED)

    progress_var = tk.DoubleVar(value=0)
    progress_bar = ttk.Progressbar(root, variable=progress_var, length=350)
    progress_bar.pack(pady=10)

    def setup_window_behaviour(force_update):
        if force_update:
            root.protocol("WM_DELETE_WINDOW", lambda: None)
            root.title(f"{APP_NAME} 更新程序 [*]")
        else:
            root.protocol("WM_DELETE_WINDOW", root.destroy)

    def update_desc_text(description):
        desc_text.config(state=tk.NORMAL)
        desc_text.delete(1.0, tk.END)
        desc_text.insert(tk.END, description)
        desc_text.config(state=tk.DISABLED)

    def startup_check_task():
        status_var.set("正在检查更新...")
        version_var.set(f"当前版本: {updater.local_version}")
        update_desc_text("正在获取更新信息...")

        if updater.check_local_update_file():
            version_var.set(f"当前版本: {updater.local_version} → 最新版本: {updater.new_version}")
            update_desc_text(updater.update_description)
            setup_window_behaviour(updater.force_update)
            root.after(1000, install_update_task)
            return

        if updater.check_update():
            version_var.set(f"当前版本: {updater.local_version} → 最新版本: {updater.new_version}")
            update_desc_text(updater.update_description)
            setup_window_behaviour(updater.force_update)

            if updater.force_update:
                status_var.set(f"发现强制更新版本: {updater.new_version}，准备下载...")
                root.after(1000, download_update_task)
            else:
                update_msg = f"发现新版本: {updater.new_version}\n\n更新内容:\n{updater.update_description}\n\n是否现在更新?"
                if messagebox.askyesno("更新提示", update_msg):
                    status_var.set(f"开始下载新版本: {updater.new_version}")
                    root.after(1000, download_update_task)
                else:
                    root.destroy()
            return

        root.destroy()

    def download_update_task():
        def update_progress(progress):
            if progress is not None:
                progress_var.set(progress)
                status_var.set(f"正在下载更新: {progress:.1f}%")
            else:
                status_var.set("正在下载更新: 大小未知")

        threading.Thread(target=updater.download_update, args=(update_progress,), daemon=True).start()

        download_complete_flag = None
        if updater.download_path:
            download_complete_flag = updater.download_path + ".complete"

        def check_download_complete():
            if progress_var.get() >= 100:
                status_var.set("下载完成，准备安装...")
                root.after(1000, install_update_task)
            else:
                if (download_complete_flag and os.path.exists(download_complete_flag)):
                    status_var.set("下载完成，准备安装...")
                    progress_var.set(100)
                    root.after(1000, install_update_task)
                else:
                    root.after(100, check_download_complete)

        root.after(100, check_download_complete)

    def install_update_task():
        if updater.install_update():
            status_var.set("更新已启动安装程序，请按照提示完成安装。")
            root.after(3000, root.destroy)
        else:
            status_var.set("安装更新失败，请手动安装。")
            root.after(3000, root.destroy)

    root.after(100, startup_check_task)
    return root


def main():
    updater = Updater()
    root = create_gui(updater)

    if updater.check_local_config() and not updater.check_update():
        root.destroy()
    else:
        root.mainloop()


if __name__ == "__main__":
    main()